import 'dart:async';
import 'dart:math';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:sonora/bloc/base/sj_base_bloc.dart';
import 'package:sonora/bloc/video/sj_video_event.dart';
import 'package:sonora/bloc/video/sj_video_state.dart';
import 'package:sonora/models/sj_block_list_item_data.dart';
import 'package:sonora/models/sj_friend_list_item_data.dart';
import 'package:sonora/models/sj_login_response_data.dart';
import 'package:sonora/models/sj_media_data.dart';
import 'package:sonora/models/sj_response_data.dart';
import 'package:sonora/repository/sj_video_repository.dart';
import 'package:sonora/utils/sj_storage_utils.dart';
import 'package:sonora/utils/sj_utils.dart';

import '../../config/sj_app_initial.dart';
import '../../events/sj_video_event.dart';

class SjVideoBloc extends SjBaseBloc<SjVideoEvent, SjVideoState> {
  final SjVideoRepository repository;
  SjVideoBloc(this.repository) : super(const SjVideoState()) {
    on<SjVideoEventTranslateText>(_onTranslateText);
    on<SjVideoEventLoaded>(_onLoadedData);
    on<SjVideoEventLikeUser>(_onLikeUser);
    on<SjVideoEventUnlikeUser>(_onUnlikeUser);
    on<SjVideoEventUnFriend>(_onUnFriend);
    on<SjVideoEventFriend>(_onAddFriend);
    on<SjVideoEventRemoveBlock>(_onRemoveBlock);
    on<SjVideoEventInsertRecord>(_onAddBlock);
    on<SjVideoEventLoadedFollowList>(_onLoadFollowList);
    on<SjVideoEventLoadedBlockList>(_onLoadBlockList);
    on<SjVideoEventInsertReport>(_onAddReport);
  }

  FutureOr<void> _onTranslateText(
      SjVideoEventTranslateText event, Emitter<SjVideoState> emit) async {
    SjResponseData responseData = await repository.mediaSearchUrl();
    if (responseData.success != null &&
        responseData.success == true &&
        responseData.data is List) {
      SjUtils.dealMediaSearchList(responseData.data);
    }
  }

  FutureOr<void> _onLoadedData(
      SjVideoEventLoaded event, Emitter<SjVideoState> emit) async {
    EasyLoading.show();
    emit(state.copyWith(loading: true));
    List<SjMediaData>? reslut = await SjStorageUtils.getMediaList();
    List<SjMediaData> list = [];
    if (reslut == null || reslut.isEmpty) {
      SjResponseData responseData = await repository.mediaSearchUrl();
      if (responseData.success != null &&
          responseData.success == true &&
          responseData.data is List) {
        reslut = await SjUtils.dealMediaSearchList(responseData.data);
      }
    }
    if (reslut == null || reslut.isEmpty) {
      EasyLoading.dismiss();
      emit(state.copyWith(mediaList: list, loading: false));
      return;
    }
    int preSize = state.mediaList?.length ?? 0;
    List<SjBlockListItemData>? blockList = await repository.blockList();
    if (blockList.isEmpty) {
      emit(state.copyWith(
          mediaList: reslut, loading: false, blokList: blockList));
      event.callback?.call(reslut);
      if (preSize == 0) {
        print('-------------------SjVideoBusEvent(isFirstPlay: true)');
        eventBus.fire(SjVideoBusEvent(isFirstPlay: true));
      }
      EasyLoading.dismiss();
      return;
    }
    bool match = false;
    for (var r in reslut) {
      match = false;
      for (var item in blockList) {
        if (r.broadCaster?.userId == item.broadcasterId) {
          match = true;
          break;
        }
      }
      if (!match) list.add(r);
    }
    emit(state.copyWith(mediaList: list, loading: false, blokList: blockList));
    event.callback?.call(list);
    if (preSize == 0) {
      print('-------------------SjVideoBusEvent(isFirstPlay: true)');
      eventBus.fire(SjVideoBusEvent(isFirstPlay: true));
    }
    EasyLoading.dismiss();
  }

  Future<void> _onLikeUser(
      SjVideoEventLikeUser event, Emitter<SjVideoState> emit) async {
    final SjLoginData? loginData = await SjStorageUtils.getLoginInfo();
    String? userId = loginData?.userInfo?.userId;
    List<SjMediaData> list = List.from(state.mediaList ?? []);
    SjMediaData? media;
    int index = 0;
    for (var element in list) {
      if (element.broadCaster != null &&
          element.broadCaster?.userId != null &&
          element.broadCaster!.userId! == event.userId &&
          element.mediaId == event.mediaId) {
        media = element;
        break;
      }
    }
    if (media != null) {
      index = list.indexOf(media);
      List<String> likedUserIdList = List.from(media.likedUserIdList ?? []);
      if (userId != null) {
        likedUserIdList.add(userId);
      }
      media = media.copyWith(isLike: true, likedUserIdList: likedUserIdList);
      SjMediaData result = SjMediaData.fromJson(media.toJson());
      list.replaceRange(index, index + 1, [result]);
    }
    SjStorageUtils.saveMedialList(list);
    emit(state.copyWith(mediaList: list));
  }

  Future<void> _onUnlikeUser(
      SjVideoEventUnlikeUser event, Emitter<SjVideoState> emit) async {
    final SjLoginData? loginData = await SjStorageUtils.getLoginInfo();
    String? userId = loginData?.userInfo?.userId;
    List<SjMediaData> list = List.from(state.mediaList ?? []);
    SjMediaData? media;
    int index = 0;
    for (var element in list) {
      if (element.broadCaster != null &&
          element.broadCaster?.userId != null &&
          element.broadCaster!.userId! == event.userId &&
          element.mediaId == event.mediaId) {
        media = element;
        break;
      }
    }
    if (media != null) {
      index = list.indexOf(media);
      List<String> likedUserIdList = List.from(media.likedUserIdList ?? []);
      if (userId != null && likedUserIdList.contains(userId)) {
        likedUserIdList.remove(userId);
      }
      media = media.copyWith(isLike: false, likedUserIdList: likedUserIdList);
      SjMediaData result = SjMediaData.fromJson(media.toJson());
      list.replaceRange(index, index + 1, [result]);
    }
    SjStorageUtils.saveMedialList(list);
    emit(state.copyWith(mediaList: list));
  }

  FutureOr<void> _onAddFriend(
      SjVideoEventFriend event, Emitter<SjVideoState> emit) async {
    SjResponseData response = await repository.addFriend(event.followUserId);
    if (response.success != null && response.success == true) {
      add(const SjVideoEvent.loadedFollowList());
      EasyLoading.showSuccess('Followed successfully',
          duration: const Duration(seconds: 2));
    }
  }

  FutureOr<void> _onUnFriend(
      SjVideoEventUnFriend event, Emitter<SjVideoState> emit) async {
    try {
      SjResponseData response = await repository.unFriend(event.followUserId);
      if (response.success != null && response.success == true) {
        List<SjFriendListItemData> list =
            List<SjFriendListItemData>.from(state.friendList ?? []);
        list.removeWhere((element) => element.userId == event.followUserId);
        emit(state.copyWith(friendList: list));
        EasyLoading.showSuccess('Unfollow Successfully',
            duration: const Duration(seconds: 2));
      }
    } catch (e) {
      emit(state.copyWith(loading: false, errorMsg: e.toString()));
    }
  }

  FutureOr<void> _onAddBlock(
      SjVideoEventInsertRecord event, Emitter<SjVideoState> emit) async {
    EasyLoading.show(status: 'Loading...');
    SjResponseData response = await repository.insertRecord(
        event.broadcasterId, event.complainCategory, event.complainSub);
    if (response.success != null && response.success == true) {
      List<SjFriendListItemData> friendList = await repository.friendList();
      if (friendList
          .where((element) => element.userId == event.broadcasterId)
          .toList()
          .isNotEmpty) {
        add(SjVideoEventUnFriend(followUserId: event.broadcasterId ?? ''));

        SjResponseData response =
            await repository.unFriend(event.broadcasterId ?? '');
        if (response.success != null && response.success == true) {
          List<SjFriendListItemData> list =
              List<SjFriendListItemData>.from(state.friendList ?? []);
          list.removeWhere((element) => element.userId == event.broadcasterId);
          emit(state.copyWith(friendList: list));
        }
      }
      EasyLoading.dismiss();
      EasyLoading.showSuccess('Block successfully',
          duration: const Duration(seconds: 2));
      // add(SjVideoEventLoaded(callback: event.videoResetCallback));
      event.videoResetCallback?.call([]);
      if (event.callback != null) {
        event.callback?.call();
      }
    }
  }

  FutureOr<void> _onAddReport(
      SjVideoEventInsertReport event, Emitter<SjVideoState> emit) async {
    SjResponseData response = await repository.insertRecord(
        event.broadcasterId, event.complainCategory, event.complainSub);
    if (response.success != null && response.success == true) {
      // add(const SjVideoEventLoaded());
      EasyLoading.showSuccess('Report successfully',
          duration: const Duration(seconds: 2));
      if (event.callback != null) {
        event.callback?.call();
      }
    }
  }

  FutureOr<void> _onRemoveBlock(
      SjVideoEventRemoveBlock event, Emitter<SjVideoState> emit) async {
    try {
      SjResponseData response =
          await repository.removeBlock(event.broadcasterId);
      if (response.success != null && response.success == true) {
        List<SjBlockListItemData> list =
            List<SjBlockListItemData>.from(state.blokList ?? []);
        list.removeWhere(
            (element) => element.broadcasterId == event.broadcasterId);
        emit(state.copyWith(blokList: list));
      }
    } catch (e) {
      emit(state.copyWith(loading: false, errorMsg: e.toString()));
    }
  }

  FutureOr<void> _onLoadBlockList(
      SjVideoEventLoadedBlockList event, Emitter<SjVideoState> emit) async {
    try {
      final list = await repository.blockList();
      emit(state.copyWith(blokList: list));
    } catch (e) {
      emit(state.copyWith(loading: false, errorMsg: e.toString()));
    }
  }

  FutureOr<void> _onLoadFollowList(
      SjVideoEventLoadedFollowList event, Emitter<SjVideoState> emit) async {
    try {
      final list = await repository.friendList();
      emit(state.copyWith(friendList: list));
    } catch (e) {
      emit(state.copyWith(loading: false, errorMsg: e.toString()));
    }
  }
}
